home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d3 / ddjhptxt.arc / MISCHEL.LST < prev    next >
File List  |  1990-06-05  |  21KB  |  518 lines

  1. LISTING ONE
  2.  
  3.         name    iter
  4.         page    ,132
  5.         title   'ITER - Enhanced MS-DOS command line processor'
  6.   ;
  7.   ; ITER.ASM
  8.   ;
  9.   ; Copyright 1989, Jim Mischel
  10.   ;
  11.   ; This program provides enhanced command line processing for MS-DOS.
  12.   ; Uses the external GETARG module for command line generation.
  13.   ;
  14.   ; Sample make file:
  15.   ;
  16.   ; # iter.mak - build iter.exe from iter.asm and getarg.asm
  17.   ; .asm.obj:
  18.   ;     tasm $<
  19.   ;
  20.   ; iter.exe: iter.obj getarg.obj
  21.   ;     tlink iter getarg
  22.   ;
  23.         ideal                           ;use TASM ideal mode
  24.         locals
  25.  
  26.         dosseg
  27.         model   small
  28.         stack   0100h
  29.  
  30.   cr            equ     0dh             ;ASCII Carriage Return
  31.   lf            equ     0ah             ;ASCII Line Feed
  32.  
  33.         DataSeg
  34.  
  35.   cmd_adr               dw      ?               ;store address of parsed com-
  36.   mand line
  37.   psp_seg               dw      ?               ;PSP segment
  38.   comspec               db      128 dup (?)     ;local storage for value of
  39.   COMSPEC
  40.   cmd_length    db      0," /C"         ;command line length
  41.   cmd_args      db      124 dup (?)     ;and arguments
  42.                 dw      ?               ;extra space for CR/LF/$
  43.   com_var               db      "COMSPEC=",0
  44.   iter_msg      db      "   ITER>> $"
  45.   errmsg                db      "Command line error.  Program
  46.   aborted",cr,lf,'$'
  47.   no_comspec    db      "ERROR: No COMSPEC environment variable."
  48.                 db      "  Program Aborted",cr,lf,'$'
  49.  
  50.   params        dw      0
  51.   pm_cmd        dw      offset cmd_length       ;seg:offset of command line
  52.         dw      seg cmd_length
  53.         dd      -1                      ;default FCB #1
  54.         dd      -1                      ;default FCB #2
  55.  
  56.  
  57.         CodeSeg
  58.  
  59.   extrn parse_cmdlin:proc               ;getarg.asm
  60.   extrn get_cmdlin:proc                 ;getarg.asm
  61.  
  62.   stk_seg       dw      ?                       ;save stack segment
  63.   stk_ptr       dw      ?                       ;save stack pointer
  64.  
  65.   proc main
  66.         mov     ax,ds                   ;get psp segment
  67.         mov     dx,@data
  68.         mov     ds,dx                   ;DS is local data segment
  69.         mov     [psp_seg],ax            ;save psp seg
  70.         cli
  71.         mov     ss,dx                   ;setup stack
  72.         mov     sp,stack
  73.         sti
  74.                                         ;adjust memory allocation
  75.         mov     es,ax                   ;psp segment in ES
  76.         mov     bx,stack                ;calculate #paragraphs needed
  77.         rept    4
  78.         shr     bx,1
  79.         endm
  80.         inc     bx
  81.         add     bx,dx                   ;add data segment value
  82.         sub     bx,ax                   ;and subtract PSP segment value
  83.         mov     ah,4ah
  84.         int     21h
  85.  
  86.         call    near ptr get_comspec    ;get COMSPEC environment variable
  87.         mov     dx,offset no_comspec
  88.         jc      main_error              ;if C set then no comspec var
  89.         mov     si,0081h                ;command line starts at 0081h
  90.         mov     ds,[psp_seg]
  91.         call    parse_cmdlin            ;parse the command line
  92.         mov     dx,@data
  93.         mov     ds,dx                   ;ds now points to local data segment
  94.         or      ax,ax                   ;if the parse returns AX=0,
  95.         mov     dx,offset errmsg
  96.         jz      main_error              ;then some error occured
  97.         mov     [cmd_adr],ax            ;save address of parsed command line
  98.  
  99.   @@loop:       mov     si,[cmd_adr]            ;command line address in DS:SI
  100.         call    get_cmdlin              ;get next command line
  101.         or      ax,ax                   ;if AX=0,
  102.         jz      main_exit               ;then no more command lines to process
  103.         mov     si,ax                   ;si is command line
  104.         mov     di,offset cmd_args
  105.         mov     bl,2                    ;command length + 2
  106.   @@lp1:        lodsb                           ;copy command line to cmd_args
  107.         stosb
  108.         inc     bl                      ;and keep track of count
  109.         or      al,al
  110.         jnz     @@lp1
  111.         mov     [cmd_length],bl         ;save command length
  112.         mov     [word ptr di-1],0d0ah   ;terminate string with CR/LF/$
  113.         mov     [byte ptr di+1],'$'
  114.         mov     ah,9
  115.         mov     dx,offset iter_msg      ;output the "ITER>>"
  116.         int     21h
  117.         mov     ah,9
  118.         mov     dx,offset cmd_args      ;and the command line
  119.         int     21h
  120.  
  121.         push    ds                      ;save segment registers
  122.         push    es
  123.         mov     [cs:stk_seg],ss         ;and stack
  124.         mov     [cs:stk_ptr],sp
  125.         mov     dx,offset comspec
  126.         mov     bx,offset params
  127.         mov     ax,4b00h                ;use DOS EXEC function
  128.         int     21h                     ;to do the command
  129.         mov     ss,[cs:stk_seg]         ;restore stack
  130.         mov     sp,[cs:stk_ptr]
  131.         pop     es                      ;and segment registers
  132.         pop     ds
  133.         jmp     short @@loop
  134.  
  135.   main_error:                           ;some error occured in parse
  136.         mov     dx,offset errmsg
  137.         mov     ah,9
  138.         int     21h                     ;output error message
  139.         mov     al,01                   ;and set error status
  140.   main_exit:                            ;arrive here with return code in AL
  141.         mov     ah,4ch
  142.         int     21h
  143.   endp main
  144.  
  145.   ;
  146.   ; GET_COMSPEC
  147.   ; Attempts to find the COMSPEC environment variable in the program's
  148.   ; environment.  If found, the value of the variable is copied to the
  149.   ; local comspec data area.
  150.   ;
  151.   ; Returns Carry = 0 on success
  152.   ;       Carry = 1 on failure
  153.   ;
  154.   proc get_comspec
  155.         mov     es,[psp_seg]
  156.         mov     es,[word ptr es:002ch]  ;get environment segment
  157.         xor     di,di                   ;ES:DI is environment pointer
  158.   gcom1:        mov     si,offset com_var       ;DS:SI is string to match
  159.         cmp     [byte ptr es:di],0      ;if this byte is 0
  160.         jnz     gcom2                   ;then there's no COMSPEC variable
  161.         stc                             ;so set carry to indicate failure
  162.         ret                             ;and exit
  163.   gcom2:        lodsb                           ;get next character in vari-
  164.   able name
  165.         or      al,al                   ;if it's 0
  166.         jz      gcom4                   ;then we've found the variable
  167.         cmp     al,[byte ptr es:di]     ;otherwise see if this char matches
  168.         jnz     gcom3                   ;the next char in environment
  169.         inc     di                      ;and if so,
  170.         jmp     short gcom2             ;continue with next character
  171.   ; Unmatched variable.  Go to end of this one & start over
  172.   gcom3:        xor     al,al                   ;gonna look for NUL terminator
  173.         mov     cx,-1
  174.         cld
  175.         repnz   scasb
  176.         jmp     short gcom1
  177.   gcom4:        mov     si,offset comspec       ;copy variable value from en-
  178.   vironment
  179.   @@loop:       mov     al,[byte ptr es:di]     ;to local COMSPEC data area
  180.         mov     [byte ptr si],al
  181.         inc     si
  182.         inc     di
  183.         or      al,al
  184.         jnz     @@loop
  185.         ret
  186.   endp get_comspec
  187.         end
  188.  
  189.  
  190. LISTING TWO
  191.  
  192.         name    getarg
  193.         page    ,132
  194.         title   'GETARG - command line generation module'
  195.   ;
  196.   ; GETARG.ASM
  197.   ;
  198.   ; Copyright 1989, Jim Mischel
  199.   ;
  200.   ; This module provides command line iteration processing for MS-DOS
  201.   ; applications.
  202.   ;
  203.         ideal                           ;use TASM ideal mode
  204.         locals
  205.  
  206.         model   small
  207.  
  208.   cr    equ     0dh                     ;ASCII Carriage Return
  209.   space equ     ' '                     ;ASCII Space
  210.   tab   equ     9                       ;ASCII Tab
  211.   hispace       equ     ' ' + 80h               ;Flag space, argument separa-
  212.   tor
  213.   lpar  equ     '(' + 80h               ;Flag left paren, start of iter list
  214.   rpar  equ     ')' + 80h               ;Flag right paren, end of iter list
  215.   in_quote      equ     1               ;mask for in-quote flag
  216.   in_space      equ     2               ;mask for in-space flag
  217.  
  218.         DataSeg
  219.  
  220.   newcmd        db      129 dup (?)             ;storage for parsed command
  221.   line
  222.   cmdlin        db      129 dup (?)             ;storage for generated command
  223.   line
  224.  
  225.         CodeSeg
  226.  
  227.   public        parse_cmdlin
  228.   public        get_cmdlin
  229.  
  230.   ;
  231.   ; PARSE_CMDLIN
  232.   ; Converts command line into form used by GET_CMDLIN and returns a pointer
  233.   ; to the parsed command line in AX.  Returns AX = 0 on error.
  234.   ;
  235.   ; Call with DS:SI pointing to the command line to be parsed.
  236.   ;
  237.   ; BP, SP, CS, DS, and SS are preserved.  Other registers may be trashed.
  238.   ;
  239.   proc parse_cmdlin
  240.         cld
  241.         mov     di,offset newcmd        ;es:di is new command line
  242.         mov     ax,seg newcmd
  243.         mov     es,ax
  244.   @@skip:       lodsb                           ;skip over leading white space
  245.         cmp     al,space
  246.         jz      @@skip
  247.         cmp     al,tab
  248.         jz      @@skip
  249.         xor     dx,dx                   ;dh is quote/space flag
  250.                                         ;dl is left paren count
  251.         jmp     short pc2               ;jump around first load
  252.   pc1:  lodsb
  253.   pc2:  cmp     al,cr                   ;if char is CR or NUL
  254.         jz      pc_done
  255.         or      al,al
  256.         jz      pc_done                 ;then we're at end
  257.         test    dh,in_quote             ;if in quote
  258.         jz      pc3
  259.         stosb                           ;store in new command line
  260.         cmp     al,'"'                  ;and check for end of quote
  261.         jnz     pc1
  262.         and     dh,not in_quote
  263.         jmp     short pc1
  264.   pc3:  cmp     al,space                ;check for separator character
  265.         jz      do_space
  266.         cmp     al,tab
  267.         jz      do_space
  268.         cmp     al,','
  269.         jnz     pc4
  270.   do_space:
  271.         test    dh,in_space             ;if already in space
  272.         jnz     pc1                     ;then ignore
  273.         mov     al,space
  274.         stosb                           ;otherwise store a space
  275.         or      dh,in_space             ;and set the space flag
  276.         jmp     short pc1
  277.   pc4:  and     dh,not in_space         ;re-set space flag
  278.         cmp     al,'"'                  ;if character is quote
  279.         jnz     pc5
  280.         stosb                           ;then store it
  281.         or      dh,in_quote             ;and set the quote flag
  282.         jmp     short pc1
  283.   pc5:  cmp     al,'('                  ;if char is left paren
  284.         jnz     pc7
  285.         or      dl,dl                   ;if left paren flag is already set
  286.         jnz     error_return            ;then we've got nested iteration
  287.         mov     al,LPAR                 ;otherwise store a left paren
  288.         stosb                           ;with the high bit set
  289.         inc     dl                      ;and set the left paren flag
  290.         jmp     short pc1
  291.   pc7:  cmp     al,')'                  ;if right paren
  292.         jnz     pc8
  293.         or      dl,dl                   ;check for left paren flag
  294.         jz      error_return            ;unbalanced if it's not set
  295.         xor     dl,dl                   ;re-set left paren flag
  296.   pc8:  stosb                           ;store the character
  297.         jmp     short pc1
  298.   pc_done:
  299.         mov     [byte ptr es:di],0      ;terminate string
  300.         cmp     al,cr                   ;check for end of string
  301.         jz      ckq
  302.         or      al,al                   ;if not at end of string
  303.         jnz     error_return            ;then error
  304.   ckq:  or      dh,dl                   ;check for unterminated strings
  305.                                         ;and unbalanced parenthesis
  306.         jnz     error_return
  307.  
  308.   good_return:
  309.         mov     ax,offset newcmd        ;return pointer to newcmd
  310.         jmp     short pc_ret
  311.   error_return:
  312.         xor     ax,ax                   ;return error status
  313.   pc_ret:       ret
  314.   endp  parse_cmdlin
  315.  
  316.   ;
  317.   ; UPDATE_ITEM
  318.   ; Update iteration pointers on the next argument in the command line.
  319.   ;
  320.   ; Call with DS:SI pointing to argument to update.
  321.   ;
  322.   ; Returns AH = 1 (and Z flag cleared) if iteration list updated
  323.   ;         AH = 0 (and Z flag set) if not.
  324.   ;
  325.   ; This is a recursive function.
  326.   ;
  327.   proc update_item
  328.         xor     ax,ax                   ;AH is quote flag
  329.         mov     bx,ax                   ;BX is list head
  330.         mov     cx,ax                   ;CX is first item
  331.         mov     di,ax                   ;DI is next item
  332.   ui1:  lodsb                           ;get next character
  333.         or      al,al                   ;if NUL,
  334.         jz      ret_0                   ;then we're done
  335.         cmp     al,'"'                  ;if quote
  336.         jnz     ui2
  337.         not     ah                      ;then flop quote flag
  338.         jmp     short ui1
  339.   ui2:  or      ah,ah                   ;if quote flag is set
  340.         jnz     ui1                     ;then just continue
  341.         cmp     al,'('                  ;if left paren
  342.         jnz     ui3
  343.   ui21: mov     bx,si                   ;then save list head pointer
  344.         jmp     short ui1
  345.   ui3:  cmp     al,lpar                 ;if flagged left paren
  346.         jnz     ui4
  347.         mov     cx,si                   ;then save first item pointer
  348.         mov     bx,si                   ;and list head pointer too
  349.         jmp     short ui1
  350.   ui4:  cmp     al,hispace              ;if high space
  351.         jnz     ui5
  352.         mov     cx,si                   ;then save first item pointer
  353.         jmp     short ui1
  354.   ui5:  cmp     al,space                ;if char is space
  355.         jnz     ui7
  356.         or      bx,bx                   ;and list head is NULL
  357.         jz      short ret_0             ;then return 0
  358.         or      cx,cx                   ;otherwise if first item is not NULL
  359.         jz      ui1
  360.         or      di,di                   ;and next item is NULL
  361.         jnz     ui1
  362.         mov     di,si                   ;then save next item pointer
  363.         jmp     short ui1
  364.   ui7:  and     al,7fh                  ;strip high bit
  365.         cmp     al,')'                  ;if character is right paren
  366.         jnz     ui1
  367.         or      di,di                   ;if next_item is NULL
  368.         jnz     ui10
  369.         mov     di,si                   ;then save next item pointer
  370.   ui10: push    bx                      ;save local variables
  371.         push    cx
  372.         push    di
  373.         call    update_item             ;update the item from here forward
  374.         pop     di                      ;restore locals
  375.         pop     cx
  376.         pop     bx
  377.         jnz     ui_ret                  ;if updated then exit
  378.         xchg    bx,cx                   ;bx is first item, cx is list head
  379.         sub     [byte ptr bx-1],80h     ;otherwise clear flag on first item
  380.         xchg    bx,cx                   ;put 'em back where they belong
  381.         mov     al,[byte ptr di-1]      ;get next item
  382.         and     al,7fh
  383.         cmp     al,')'                  ;if it's the end of an iteration list
  384.         jnz     ui8
  385.         mov     [byte ptr di-1],rpar    ;then set the done flag
  386.         mov     [byte ptr bx-1],lpar    ;and re-initialize the list
  387.   ret_0:        xor     ah,ah                   ;0 means no update
  388.         ret
  389.   ui8:  add     [byte ptr di-1],80h     ;not at end of list so set space flag
  390.   ret_1:        mov     ah,1                    ;1 signifies update occured
  391.         or      ah,ah                   ;set Z flag to reflect return status
  392.   ui_ret:       ret
  393.   endp update_item
  394.  
  395.   ;
  396.   ; NEXT_ITER
  397.   ; Update the command line for the next iteration.
  398.   ;
  399.   ; Returns the last character scanned.  If the last char scanned is
  400.   ; 0 (the string terminator), then all command lines have been generated.
  401.   ;
  402.   ; Call with DS:SI pointing to the command line to be updated.
  403.   ;
  404.   proc next_iter
  405.         push    si                      ;save beginning of command line
  406.   @@loop:       call    update_item
  407.         cmp     [byte ptr si],0
  408.         jnz     @@loop                  ;update each item
  409.         pop     si                      ;restore command line address
  410.         mov     di,si                   ;save it here in case we need it
  411.   ;
  412.   ; If the string terminator (0) is found, then all command lines have
  413.   ; been generated.
  414.   ; If a right paren (unflagged) is found, then there's still more work to do.
  415.   ;
  416.   @@lp1:        lodsb
  417.         cmp     al,')'
  418.         jz      @@done
  419.         or      al,al
  420.         jnz     @@lp1
  421.         mov     [byte ptr di],al        ;end of command lines, store NUL
  422.   @@done:       ret
  423.   endp next_iter
  424.  
  425.   ;
  426.   ; GET_CMDLIN
  427.   ; Generates the next command line and returns a pointer to it in AX
  428.   ; Returns AX = 0 if all command lines have been generated.
  429.   ;
  430.   ; Call with DS:SI pointing to the parsed command line.
  431.   ;
  432.   ; BP, SP, SS and DS are saved by this routine.  All other registers may
  433.   ; be destroyed.
  434.   ;
  435.   proc get_cmdlin
  436.         cmp     [byte ptr si],0         ;if command line is empty
  437.         jnz     gc1
  438.         xor     ax,ax                   ;then return NULL
  439.         ret
  440.         cld                             ;gotta do this!
  441.   gc1:  push    si                      ;save command line address
  442.         mov     ax,seg cmdlin
  443.         mov     es,ax
  444.         mov     di,offset cmdlin        ;ES:DI is generated command line
  445.         mov     dx,0200h                ;dh is copy flag
  446.                                         ;2 = unconditional copy
  447.                                         ;1 = copy to end of arg
  448.                                         ;0 = no copy
  449.                                         ;dl is quote flag
  450.  
  451.   gc2:  lodsb                           ;get next character
  452.         or      al,al                   ;if NUL,
  453.         jz      gc_done
  454.         cmp     al,cr                   ;or CR...
  455.         jz      gc_done                 ;then we're done
  456.         or      dl,dl                   ;otherwise, if in quote
  457.         jz      gc4
  458.         or      dh,dh                   ;and in copy
  459.         jz      gc3
  460.         stosb                           ;then save the character
  461.   gc3:  cmp     al,'"'                  ;if character is quote
  462.         jnz     gc2
  463.         not     dl                      ;then re-set quote flag
  464.         jmp     short gc2
  465.   gc4:  cmp     al,'"'                  ;if character is quote
  466.         jnz     gc5
  467.         not     dl                      ;set the quote flag
  468.         or      dh,dh                   ;if in copy
  469.         jz      gc2
  470.         stosb                           ;then store the character
  471.         jmp     short gc2
  472.   gc5:  or      dh,dh                   ;dispatch to proper routine
  473.         jz      copy_0                  ;depending on value of DH (copy flag)
  474.         cmp     dh,1
  475.         jz      copy_1
  476.   copy_2:       cmp     al,'('                  ;if character is '('
  477.         jnz     c21
  478.         xor     dh,dh                   ;then clear copy flag
  479.         jmp     short gc2
  480.   c21:  cmp     al,lpar                 ;if char is lpar
  481.         jz      c22
  482.         cmp     al,hispace              ;or hispace
  483.         jnz     c23
  484.   c22:  mov     dh,1                    ;then set copy to 1
  485.         jmp     short gc2
  486.   c23:  stosb                           ;otherwise store the character
  487.        jmp     short gc2
  488.  
  489.   copy_1:       cmp     al,space                ;if char is space
  490.         jnz     c11
  491.         xor     dh,dh                   ;then clear copy flag
  492.         jmp     short gc2
  493.   c11:  cmp     al,')'                  ;if character is right paren
  494.         jz      c12
  495.         cmp     al,rpar                 ;or flagged right paren...
  496.         jnz     c23                     ;(it's neither, store and go)
  497.   c12:  mov     dh,2                    ;...then set the copy flag
  498.         jmp     short gc2
  499.  
  500.   copy_0:       cmp     al,')'                  ;if character is not right
  501.   paren
  502.         jz      c12
  503.         cmp     al,rpar                 ;or flagged right paren
  504.         jz      c12
  505.         cmp     al,hispace              ;if it's hispace
  506.         jz      c22                     ;then set copy to 1
  507.         jmp     short gc2               ;otherwise just ignore it
  508.  
  509.   gc_done:                              ;done generating command line
  510.         xor     al,al
  511.         stosb                           ;terminate string with NUL byte
  512.         pop     si                      ;restore command line address
  513.         call    next_iter               ;and update for next iteration
  514.         mov     ax,offset cmdlin        ;return address of...
  515.         ret                             ;... generated command line
  516.   endp get_cmdlin
  517.  
  518.         end